package com.fudan.framework.base;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fudan.framework.annotation.PAdd;
import com.fudan.framework.annotation.PDelete;
import com.fudan.framework.annotation.PUpdate;
import com.fudan.framework.annotation.PView;
import com.fudan.framework.annotation.Permissions;
import com.fudan.framework.entity.RequestEntity;
import com.fudan.framework.entity.ResponseMsg;
import com.fudan.framework.utils.EntityUtils;

/**
 * 
 * @author Xuxinxing
 *
 * @param <T>
 */
@Deprecated
public abstract class DataController<T extends RequestEntity> extends BaseController {

    abstract protected DaoService<T> injectService();

    abstract protected String pathPrefix();

    @RequestMapping("/p/{path}")
    public String findPage(@PathVariable("path") String path) {
        StringBuilder p = new StringBuilder();
        p.append(pathPrefix()).append("/").append(path);
        return p.toString();
    }

    @RequestMapping("/add")
    @ResponseBody
    final public ResponseMsg doAdd(HttpServletRequest request) {
        try {
            checkPermission("add");
            boolean result = add(request);
            if (result) {
                return ResponseMsg.build(SUCCESS_CODE, SUCCESS);
            } else {
                return ResponseMsg.build(ADD_ERROR_CODE, ERROR);
            }
        } catch (Exception e) {
            return ResponseMsg.build(SYSTEM_ERROR_CODE, e.getMessage());
        }
    }

    public Boolean add(HttpServletRequest request) throws Exception {
        T entity = EntityUtils.toEntity(request, getActualClass());
        boolean result = injectService().add(entity);
        return result;
    }

    @RequestMapping("/delete")
    @ResponseBody
    final public ResponseMsg doDelete(HttpServletRequest request) {
        try {
            checkPermission("delete");
            Boolean result = delete(request);
            if (result) {
                return ResponseMsg.build(SUCCESS_CODE, SUCCESS);
            } else {
                return ResponseMsg.build(DELETE_ERROR_CODE, "删除失败");
            }
        } catch (Exception e) {
            return ResponseMsg.build(SYSTEM_ERROR_CODE, "删除失败");
        }
    }

    public Boolean delete(HttpServletRequest request) {
        String id = request.getParameter("id");
        Boolean result = injectService().delete(id);
        return result;
    }

    @RequestMapping("/deletes")
    @ResponseBody
    final public ResponseMsg doDeteleBatch(HttpServletRequest request) {
        checkPermission("delete");
        try {
            Boolean result = deleteBatch(request);
            if (result) {
                return ResponseMsg.build(SUCCESS_CODE, SUCCESS);
            } else {
                return ResponseMsg.build(ADD_ERROR_CODE, ERROR);
            }
        } catch (Exception e) {
            return ResponseMsg.build(SYSTEM_ERROR_CODE, e.getMessage());
        }
    }

    public Boolean deleteBatch(HttpServletRequest request) throws Exception {
        String[] ids = request.getParameterValues("ids");
        List<T> list = new ArrayList<>();
        for (String id : ids) {
            T t = injectService().get(id);
            //t.fill("discard", true);
            list.add(t);
        }
        Boolean result = injectService().deleteBatch(list);
        return result;
    }

    @RequestMapping("/update")
    @ResponseBody
    final public ResponseMsg doUpdate(HttpServletRequest request) throws Exception {
        checkPermission("update");
        try {
            Boolean result = update(request);
            if (result) {
                return ResponseMsg.build(SUCCESS_CODE);
            } else {
                return ResponseMsg.build(UPDATE_ERROR_CODE, "更新失败");
            }
        } catch (Exception e) {
            return ResponseMsg.build(SYSTEM_ERROR_CODE, e.getMessage());
        }
    }

    public Boolean update(HttpServletRequest request) throws Exception {
        T entity = EntityUtils.toEntity(request, getActualClass());
        boolean result = injectService().update(entity);
        return result;
    }

    @RequestMapping("/find")
    @ResponseBody
    final public ResponseMsg doFind(HttpServletRequest request) {
        checkPermission("find");
        return ResponseMsg.build(SUCCESS_CODE).put("data", find(request));
    }

    public T find(HttpServletRequest request) {
        String id = request.getParameter("id");
        return injectService().get(id);
    }

    @SuppressWarnings("unchecked")
    private Class<T> getActualClass() {
        Type superclass = this.getClass().getGenericSuperclass();
        if (superclass instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) superclass;
            try {
                return (Class<T>) Class.forName(pType.getActualTypeArguments()[0].getTypeName());
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("泛型无法创建", e);
            }
        }
        throw new RuntimeException("不能获取泛型信息");
    }

    private void checkPermission(String action) {
        Subject subject = SecurityUtils.getSubject();
        Class<?> realClass = this.getClass();
        String permissionCode = null;
        String[] perStr = null;
        try {
            Permissions permissions = this.getClass().getAnnotation(Permissions.class);
            if (permissions != null) {
                perStr = permissions.value();
            }
        } catch (SecurityException e1) {
            e1.printStackTrace();
        }
        switch (action) {
            case "add": {
                permissionCode = extractPermissionCode(perStr, 0);
                PAdd padd = realClass.getAnnotation(PAdd.class);
                if (padd != null) {
                    permissionCode = padd.value();
                }
                break;
            }
            case "delete": {
                permissionCode = extractPermissionCode(perStr, 1);
                PDelete pDelete = realClass.getAnnotation(PDelete.class);
                if (pDelete != null) {
                    permissionCode = pDelete.value();
                }
                break;
            }
            case "update": {
                permissionCode = extractPermissionCode(perStr, 2);
                PUpdate pUpdate = realClass.getAnnotation(PUpdate.class);
                if (pUpdate != null) {
                    permissionCode = pUpdate.value();
                }
                break;
            }
            case "find": {
                permissionCode = extractPermissionCode(perStr, 3);
                PView pView = realClass.getAnnotation(PView.class);
                if (pView != null) {
                    permissionCode = pView.value();
                }
                break;
            }
            default: {
                break;
            }
        }
        if (permissionCode != null && !"".equals(permissionCode)) {
            subject.checkPermission(permissionCode);
        }
    }

    private String extractPermissionCode(String[] codes, int index) {
        if (codes == null || codes.length != 4 || index < 0 || index > 3) {
            return null;
        }
        return codes[index];
    }
}
